package dsx.mongo;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoCredential;
import com.mongodb.ReadPreference;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;

class MongoDrv {

	private String serverName;
	private MongoClient mongoClient;

	public MongoDrv(String serverName) throws Exception {
		this.serverName = serverName;
		List<ServerAddress> addresses = getServerAddresses(serverName + ".xml");
		List<MongoCredential> credentials = getCredentials(serverName + ".xml");
		if (addresses.size() == 1) {
			MongoClientOptions options = MongoClientOptions.builder().connectionsPerHost(100)
					.threadsAllowedToBlockForConnectionMultiplier(10).maxWaitTime(100).connectTimeout(0)
					.socketTimeout(0).readPreference(ReadPreference.secondaryPreferred())
					.writeConcern(WriteConcern.ACKNOWLEDGED).build();

			this.mongoClient = new MongoClient(addresses.get(0), credentials, options);
		} else {
			MongoClientOptions options = MongoClientOptions.builder().connectionsPerHost(500)
					.threadsAllowedToBlockForConnectionMultiplier(10).maxWaitTime(30).connectTimeout(0).socketTimeout(0)
					.readPreference(ReadPreference.nearest()).writeConcern(WriteConcern.MAJORITY).build();
			this.mongoClient = new MongoClient(addresses, credentials, options);
		}
	}

	public String getServerName() {
		return this.serverName;
	}

	public void close() {
		this.mongoClient.close();
	}

	public MongoCollection<org.bson.Document> getCollection(String dbName, String collectionName) {
		MongoDatabase db = mongoClient.getDatabase(dbName);
		if (db != null)
			return db.getCollection(collectionName);
		else
			return null;
	}

	public DBCollection getDBCollection(String dbName, String collectionName) {
		@SuppressWarnings("deprecation")
		DB db = mongoClient.getDB(dbName);

		if (db != null)
			return db.getCollection(collectionName);
		else
			return null;
	}

	private List<ServerAddress> getServerAddresses(String configFile) throws Exception {
		List<ServerAddress> addresses = new ArrayList<ServerAddress>();
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document document = db.parse(new File(configFile));
		Element root = document.getDocumentElement();
		NodeList modules = root.getElementsByTagName("Server");
		int moduleNum = modules.getLength();
		for (int i = 0; i < moduleNum; i++) {
			String ip;
			NodeList elem = ((Element) modules.item(i)).getElementsByTagName("ip");
			if (elem.getLength() > 0)
				ip = elem.item(0).getTextContent();
			else
				continue;
			int port;
			elem = ((Element) modules.item(i)).getElementsByTagName("port");
			if (elem.getLength() > 0)
				port = parseInt(elem.item(0).getTextContent());
			else
				continue;
			addresses.add(new ServerAddress(ip, port));
		}
		return addresses;
	}

	private List<MongoCredential> getCredentials(String configFile) throws Exception {
		List<MongoCredential> credentials = new ArrayList<MongoCredential>();

		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document document = db.parse(new File(configFile));
		Element root = document.getDocumentElement();
		NodeList modules = root.getElementsByTagName("Database");
		int moduleNum = modules.getLength();
		for (int i = 0; i < moduleNum; i++) {
			String database;
			NodeList elem = ((Element) modules.item(i)).getElementsByTagName("name");
			if (elem.getLength() > 0)
				database = elem.item(0).getTextContent();
			else
				continue;
			String user;
			elem = ((Element) modules.item(i)).getElementsByTagName("user");
			if (elem.getLength() > 0)
				user = elem.item(0).getTextContent();
			else
				continue;
			String password;
			elem = ((Element) modules.item(i)).getElementsByTagName("password");
			if (elem.getLength() > 0)
				password = elem.item(0).getTextContent();
			else
				continue;
			credentials.add(MongoCredential.createCredential(user, database, password.toCharArray()));
		}

		return credentials;
	}

	private static int parseInt(String s) {
		try {
			return Integer.parseInt(s);
		} catch (Exception ex) {
			return -1;
		}
	}
}
